package bimvu.lab21;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.http.AndroidHttpClient;
import android.os.AsyncTask;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.ListView;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

class UrlDownloaderTask extends AsyncTask<String, Integer, Bitmap> implements DialogInterface.OnCancelListener {
    private static final int NUMBER_OF_STEPS = 100;
    private static final int TEMP_BUFFER_SIZE = 1024;
    public static final int BITS_PER_BYTE = 8;
    public static final int MILLISECONDS_PER_SECOND = 1000;

    private String url;
    private final WeakReference<Context> parentContext;
    private ProgressDialog pd;
    private long downloadedSize;
    private float averageSpeed;

    public UrlDownloaderTask(final Context context) {
        parentContext = new WeakReference<Context>(context);
    }

    @Override
    // Actual download method, run in the task thread
    protected Bitmap doInBackground(String... params) {
        // params comes from the execute() call: params[0] is the url.
        return downloadBitmap(params[0]);
    }

    @Override
    protected void onPreExecute() {
        pd = new ProgressDialog(parentContext.get());
        pd.setTitle("Downloading...");
        pd.setCancelable(true);
        pd.setOnCancelListener(this);
        pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        pd.setMax(NUMBER_OF_STEPS);
        pd.show();
    }

    @Override
    protected final void onProgressUpdate(final Integer... progress) {
        pd.setProgress(progress[0]);
    }

    @Override
    // Once the image is downloaded, associates it to the imageView
    protected void onPostExecute(Bitmap bitmap) {
        pd.dismiss();
        if (isCancelled()) {
            bitmap = null;
        }
        else {
            DownloadedContentActivity downloadedContentActivity = (DownloadedContentActivity) parentContext.get();
            downloadedContentActivity.updateDownloadedContentView(bitmap, downloadedSize, averageSpeed);
        }
    }

    private Bitmap downloadBitmap(String urlString) {

        URL url = createUrlObject(urlString);
        HttpURLConnection urlConnection = getHttpURLConnection(url);
        long totalSize = urlConnection.getContentLength();

        InputStream inputStream = getInputStreamFromConnection(urlConnection);

        long timeStart = System.currentTimeMillis();
        int bytesCount;
        downloadedSize = 0;
        byte[] tempBuffer = new byte[TEMP_BUFFER_SIZE];

        ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
        try {
            while ((bytesCount = inputStream.read(tempBuffer)) > 0) {
                dataStream.write(tempBuffer, 0, bytesCount);
                downloadedSize += bytesCount;
                updateProgress(downloadedSize, totalSize);
            }
        }
        catch (IOException e) {
            throw new RuntimeException("Can not read from input stream", e);
        }
        finally {
            closeInputStream(inputStream);
            urlConnection.disconnect();
        }

        long timeFinish = System.currentTimeMillis();
        long timeDiff = timeFinish - timeStart;

        averageSpeed = getSpeed(downloadedSize, timeDiff);
        ByteArrayInputStream resultStream = new ByteArrayInputStream(dataStream.toByteArray());

        return BitmapFactory.decodeStream(resultStream);
    }

    private static HttpURLConnection getHttpURLConnection(URL url) {
        HttpURLConnection urlConnection;
        try {
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setDoOutput(false);
            urlConnection.setInstanceFollowRedirects(true);
            urlConnection.connect();
        }
        catch (IOException e) {
            throw new RuntimeException("Can not connect by url", e);
        }
        return urlConnection;
    }

    private static URL createUrlObject(String url) {
        try {
            return new URL(url);
        }
        catch (MalformedURLException e) {
            throw new RuntimeException("Invalid url", e);
        }
    }

    private static InputStream getInputStreamFromConnection(URLConnection urlConnection) {
        try {
            return urlConnection.getInputStream();
        }
        catch (IOException e)
        {
            throw new RuntimeException("Can't connect by url", e);
        }
    }

    private static void closeInputStream(InputStream inputStream) {
        try {
            inputStream.close();
        }
        catch (IOException e) {
            throw new RuntimeException("Can not close input stream", e);
        }
    }

    /**
     *
     * @param bytesCount
     * @param passedMilliseconds
     * @return downloadSpeedInKyloBits
     */
    private static float getSpeed(long bytesCount, long passedMilliseconds)
    {
        return (bytesCount * BITS_PER_BYTE * 1.0f) / (passedMilliseconds);
    }

    private void updateProgress(long curr, long total) {
        publishProgress(Math.round(((curr * 1.0f) / total) * NUMBER_OF_STEPS));
    }

    @Override
    public final void onCancel(final DialogInterface dialog) {
        pd.dismiss();
        cancel(true);
    }

}

